﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DocumentController.cs" company="DST Nexdox">
//   Copyright (c) DST Nexdox. All rights reserved.
// </copyright>
// <summary>
//   Defines the DocumentController type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace UnityWeb.Controllers
{
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Web.Mvc;
  using ClientProxies.ArchiveServiceReference;
  using Entities;
  using Logging;
  using ServiceInterfaces;
  using UnityWeb.Filters;
  using UnityWeb.Models.Document;
  using UnityWeb.Models.Search;

  [AuthorizeLoggedInUser]
  public class DocumentController : BaseController
  {
    private const Int32 PageSize = 10;

    private readonly IDocumentService documentService;
    private readonly IUserService userService;
    private readonly IManCoService manCoService;

    public DocumentController(
        IDocumentService documentService,
        IUserService userService,
        IManCoService manCoService,
        ILogger logger)
      : base(logger)
    {
      this.documentService = documentService;
      this.userService = userService;
      this.manCoService = manCoService;
    }

    [HttpGet]
    public ActionResult Index()
    {
      var model = new DocumentsViewModel();

      this.TempData["valid"] = "Show filter";
      return this.View("Search", model);
    }

    public ActionResult SearchGrid(String grid, Int32 page = 1, Boolean isAjaxCall = false, Boolean filterHouseHolding = false, Boolean filterUnapproved = false, Boolean filterApproved = false)
    {
      var documentsViewModel = new DocumentsViewModel(grid, filterHouseHolding);

      PagedResult<IndexedDocumentData> documents = this.documentService.GetDocuments(page, PageSize, grid, filterHouseHolding, filterUnapproved, filterApproved);

      documentsViewModel.AddDocuments(documents);

      this.ApplyDataFromLocalDatabase(documentsViewModel);

      documentsViewModel.AddTotalDocs(this.documentService.GetDocumentCount(grid));
      documentsViewModel.AddDocsAwaitingApproval(this.documentService.GetUnApprovedDocumentsCount(grid));
      documentsViewModel.AddDocsApproved(this.documentService.GetApprovedDocumentsCount(grid));

      if (isAjaxCall)
      {
        return this.PartialView("_PagedDocumentResults", documentsViewModel);
      }

      return this.View("Search", documentsViewModel);
    }

    public ActionResult Show(String documentId)
    {
      Byte[] document = this.documentService.GetDocumentStream(documentId);
      MemoryStream memoryStream = this.ConvertToStream(document);
      return this.File(memoryStream, "application/pdf");
    }

    public ActionResult Search(SearchViewModel searchViewModel, Int32 page = 1, Boolean isAjaxCall = false)
    {
      this.Session["SearchViewModel"] = null;

      if (!ModelState.IsValid)
      {
        var errorList = ModelState.Values.SelectMany(x => x.Errors).ToList();
        this.TempData["error"] = errorList[0].ErrorMessage;
        return new RedirectResult(Request.Headers["Referer"]);
      }

      this.PopulateManCoTextList(searchViewModel);

      this.AddSearchViewModelToSession(searchViewModel);

      var documentsViewModel = new DocumentsViewModel();

      PagedResult<IndexedDocumentData> documents = this.documentService.GetDocuments(
        page,
        PageSize,
        searchViewModel.SelectedDocText,
        searchViewModel.SelectedSubDocText,
        searchViewModel.AddresseeSubType,
        searchViewModel.AccountNumber,
        searchViewModel.MailingName,
        searchViewModel.ManCoTexts,
        searchViewModel.InvestorReference,
        searchViewModel.ProcessingDateFrom,
        searchViewModel.ProcessingDateTo,
        searchViewModel.PrimaryHolder,
        searchViewModel.AgentReference,
        searchViewModel.AddresseePostCode,
        searchViewModel.EmailAddressSearch,
        searchViewModel.FaxNumberSearch,
        searchViewModel.ContractDate,
        searchViewModel.PaymentDate,
        searchViewModel.DocumentNumber);

      documentsViewModel.AddDocuments(documents);

      this.ApplyDataFromLocalDatabase(documentsViewModel);

      this.TempData["valid"] = "Show filter";

      if (documents.Results.Count == 0 && documents.TotalItems > 0)
      {
        this.TempData["tooManyDocs"] = "There were too many documents returned from your search. Please refine your search criteria";
      }
      else
      {
        this.TempData["tooManyDocs"] = string.Empty;
      }

      if (isAjaxCall)
      {
        return this.PartialView("_PagedDocumentResults", documentsViewModel);
      }

      return this.View(documentsViewModel);
    }

    public ActionResult PdfContainer(String documentId)
    {
      return this.PartialView("_PdfContainer", documentId);
    }

    public ActionResult Status(String documentId)
    {
      Document document = this.documentService.GetDocument(documentId);

      return this.PartialView(
        "_DocumentStatus",
        document != null ? new DocumentStatusViewModel(document) : new DocumentStatusViewModel());
    }

    [OutputCache(CacheProfile = "medium", VaryByParam = "document")]
    private MemoryStream ConvertToStream(Byte[] document)
    {
      var memoryStream = new MemoryStream();
      memoryStream.Write(document, 0, document.Length);
      memoryStream.Position = 0;

      HttpContext.Response.AddHeader("content-disposition", "inline; filename=myPDF.pdf");
      return memoryStream;
    }

    private void AddSearchViewModelToSession(SearchViewModel searchViewModel)
    {
      if (this.HttpContext.Session == null)
      {
        // To hide resharper warning
        throw new Exception("Session cannot be null");
      }

      this.HttpContext.Session["SearchViewModel"] = searchViewModel;
    }

    private void PopulateManCoTextList(SearchViewModel searchViewModel)
    {
      if (searchViewModel.SelectedManCoText == null)
      {
        searchViewModel.ManCoTexts = this.GenerateMancoTextList().ToList();
      }
      else
      {
        searchViewModel.ManCoTexts.Add(searchViewModel.SelectedManCoText.Trim());
      }
    }

    private IList<String> GenerateMancoTextList()
    {
      var manCoTextList = new List<String>();

      ApplicationUser currentUser = this.userService.GetApplicationUser();
      IList<ManCo> manCos = this.manCoService.GetManCosByUserId(currentUser.Id);

      foreach (ManCo manCo in manCos)
      {
        manCoTextList.Add(manCo.Code);
      }

      return manCoTextList;
    }

    private void ApplyDataFromLocalDatabase(DocumentsViewModel docViewModel)
    {
      List<DocumentViewModel> documentsFromArchive = docViewModel.Documents;

      IEnumerable<Document> documents = this.documentService.GetDocuments(documentsFromArchive.Select(d => d.DocumentId));

      var documentsFromBothSources = documentsFromArchive.Join(
        documents,
        dvm => dvm.DocumentId,
        docSummary => docSummary.DocumentId,
        (dvm, docSummary) => new { DocumentViewModel = dvm, DocumentSummary = docSummary });

      foreach (var doc in documentsFromBothSources)
      {
        DocumentViewModel documentViewModel = doc.DocumentViewModel;
        Document document = doc.DocumentSummary;

        documentViewModel.AddCheckoutDetails(document);
        documentViewModel.AddApprovalDetails(document);
        documentViewModel.AddRejectionDetails(document);
        documentViewModel.AddGridRunDetails(document);
        documentViewModel.AddManCoDetails(document);
        documentViewModel.AddDoNotPrintFlag(document);
      }
    }
  }
}
